/**
 * 1.持久化方式和异同
 *      1.RDB:快照的方式，将缓存存储为一个文件，单独开辟一个fork子进程执行，不影响系统功能，可以设置多少秒或者多大快照一次
 *          容灾好，安全性低，容易丢失数据，恢复时间快
 *      2.AOF:日志形式持久化，保存redis的执行命令，每秒同步
 *          宕机丢失1s的数据，数据量大，回复时间慢
 *          rewrite机制，定期对AOF文件进行重写，压缩文件
 * 2.redis过期键删除策略
 *      1.定期删除：每过一段时间，从一定数量的数据库中取出一定数量的随机键进行检查，并删除其中的过期键
 *      2.定时删除：在设置过期时间的时候设置一个定时器，让定时器到期了就删除key，占用内存小，但是cpu消耗大
 *      3.惰性删除：设置过期时间的键，过期了不自动删除，等要查询到的时候，发现过期了，就删除，返回null，占用空间大
 * 3.redis线程模型，单线程为什么那么快：
 *      1.IO多路复用技术：同步非阻塞的IO，reactor事件驱动响应模式
 *      2.纯内存操作，数据都存放在内存中，内存的响应时间大概在100纳秒，这是redis处理每秒万级数据的根本
 *      3.单线程：省去了多线程时CPU上下文切换的时间，也不用去考虑各种锁的问题，不存在加索释放锁的操作，没有死锁问题导致的性能消耗
 * 4.缓存穿透，缓存雪崩，缓存击穿
 *      1.缓存穿透：某个key不存在，但却有请求一直查询这个Key，就查询到了数据库，数据库查询也不存在，就对数据库造成了压力。
 *        一般是黑客攻击，查询了比如id为-1的一条数据。可以用布隆过滤器解决，或者代码中对一些特殊的请求做过滤
 *      2.缓存雪崩：在某个时间大量的key同时过期，导致同时查询数据库，对数据库造成压力，进而导致服务统统崩溃。可以在缓存失效
 *        时间上加一个随机的时间戳，key不会同时过期
 *      3.缓存击穿：某个key过期了，但是这时候有大量的请求查询这个key，一瞬间对数据库造成压力。可以将某些key设置为永久或者
 *        设置定时器在业务量小的时候定时刷新这些Key
 * 5.redis事务
 *      1.WATCH:乐观锁，监控一个或者多个键，一旦被修改，之后的事务不会执行
 *      2.MULTI：开启一个事务，当EXEC被调用时候，才会结束事务
 *      3.EXEC：结束事务
 *      4.DISCARD：清空事务队列
 *      5.UNWATCH：取消对Key的监控
 * 6.redis集群方案：
 *      1.哨兵模式：
 *          集群监控：负责监控redis master和slave的进程是否正常
 *          消息通知：如果某个redis有故障，那么哨兵负责发送消息报警
 *          故障转移：如果master挂了，会自动转移到slave上
 *          配置中心：如果故障转移发生了，通知client客户端新的Master地址
 *          哨兵+redis主从部署架构，不保证数据零丢失，保证高可用
 *          集群选举原理：
 *              1.步骤
 *                  1.故障节点主观下线：每隔1s会对节点发送ping命令做心跳监测，当节点超过一定阈值（可配置）没有回复，则sentinel节点会对该节点做失败判定，叫做主观下线
 *                  2.故障节点客观下线：当主观下线的节点是主节点时，sentinel会让其它的sentinel对这个主节点进行判断，如果超过阈值，就确认它确实有问题，这时sentinel
 *                    会做出客观下线的决定，也就是大部分sentinel节点判定那个主节点主观下线，则判断它客观下线
 *                  3.sentinel集群选举领导者：当发现主节点主观下线时，并不会立刻故障转移，而是进行sentinel领导者选举，让领导者去完成故障转移的工作
 *                      1.每个Sentinel节点都有资格成为领导者，当它确认主节点主观下线时，会向其他Sentinel节点发送sentinel is-master-down-by-addr命令，
 *                        要求将自己设置为领导者
 *                      2.收到命令的Sentinel节点，如果没有同意过其他Sentinel节点的sentinel is-master-down-by-addr命令，将同意该请求，否则拒绝
 *                      3.如果该Sentinel节点发现自己的票数已经大于等于max(quorum, num(sentinels)/2+1)，那么它将成为领导者
 *                      4.如果此过程没有选举出领导者，将进入下一次选举
 *                  4.sentinel集群选举新主节点（故障转移）
 *                      1.Sentinel领导者对1中选举出来的从节点执行slaveof no one命令，让其成为主节点
 *                      2.Sentinel领导者向剩余的从节点发送命令，让它们成为新主节点的从节点
 *                      3.Sentinel节点集合会将原来的主节点更新为从节点，并保持对其关注，当其恢复后命令它去复制新的主节点
 *              2.
 *      2.redis cluster
 *          1.通过hash，进行分片，将数据分配到16384个漕上
 *          2.每份数据分片会存储在多个互为主从的多节点上
 *          3.数据先写入主节点，再从主节点同步到从节点
 *          4.读取数据，当客户端操作的key没有分配到该节点上，redis会返回转向指令，指向正确的节点
 *          5.扩容时需把旧节点的数据迁移一部分到新节点上，采用虚拟hash槽分区，不是一致性hash
 *          6.缺点：
 *              1.只能用0号数据库
 *              2.不支持批量操作，不支持使用mset,mget,pipeline等操作
 *                  1.可以在客户端先预先计算出hash槽的位置，然后获取到节点的位置，最后统一进行批量操作，jedis是有这个实现
 *              3.从节点只有一个，而且是作为冷备的，不支持读
 *              4.数据的复制是异步复制，无法保证强一致性
 *      3.redis sharding
 *          1.hash将key散列，映射到redis节点上，放到客户端处理
 *      4.三种模式的比较
 *          1.主从模式可以支持主从复制和读写分离，但是不具备容错和恢复的功能，如果master节点挂了就无法提供服务，而且数据存储容量无法横向扩展
 *          2.哨兵模式引入了集群监控的特性，可以监控主从集群的健康，如果master节点宕机，则会自动选举slave节点为master节点，继续提供服务，保证高可用
 *            ，但是还是无法进行数据的横向扩展
 *          3.redis-cluster模式，多个实例之间两两相通，互为主从，可定义数据存储的副本数量，分成16384个槽，将数据均匀分散到各个节点中去。
 *            如果一个master节点挂了，可以选举它的从节点继续提供服务。而且数据可以横向扩展，解决单机内存不足的问题
 * 7.主从复制
 *      1.全量复制
 *          1.主节点通过bgsave命令fork一个子进程进行rdb
 *          2.主节点通过网络将rdb文件传给子节点
 *          3.从节点清空老数据，载入rdb文件
 *      2.部分复制
 *          1.主从节点各自维护一个复制偏移量
 *          2.主节点维护一个固定长度的，先进先出的队列作为复制缓冲区，当主从节点的offset长度差距超过缓冲区大小，则全量复制
 *          3.根据redis id判断复制的进度
 *      3.过程
 *          1.从服务器收到slaveof命令，判断是否执行第一次复制
 *          2.向master发送psync命令，master返回fullsync 和master的id和偏移量，再执行全量同步或者增量同步
 * 8.redis底层数据结构：
 *      1.string
 *          1.动态字符串SDS，一个字符数组，底层c语言实现
 *          2.set aa bb ，其实是创建了两个SDS，一个是名为aa的key SDS，一个是名为 bb 的value SDS，就算是list类型也是由很多个SDS构成
 *          3.SDS结构：字符数组，free剩余空间，长度，key长度最大是512M
 *          4.为什么不用C语言的字符串而用SDS？
 *              1.获取长度时间O1
 *              2.杜绝缓冲区溢出：在做字符串拼接的时候，如果C没提前计算内存，会导致缓冲溢出，而SDS存储了free，未扩容的长度，可以进行扩容
 *              3.减少字符串修改时候带来的内存重新分配次数
 *              4.二进制安全：C字符串以\0结尾，遇上\0就结束了，如果是什么图片的压缩数据，就不能识别，redis可以保存二进制小文件
 *      2.zsort
 *          1.跳跃表：结构详看数据结构那边
 *              1.为什么使用跳跃表，不用红黑树
 *                  1.要实现随机的插入和删除，数组的插入和删除都是On
 *                  2.在高并发下，数需要做一些reblance的操作来平衡结构，涉及性能，而跳跃表只需要变化局部，完全依靠随机，跳跃表实现更加简单
 *              2.跳跃表的实现
 *                  1.随机层数：原始结构是抛硬币法
 *                  2.最大层数是32
 *                  3.redis中zsort比较大小不仅会比较排名，还会比较值
 *      3.list
 *          1.redis内部自己实现了无环的双端链表ListNode
 *          2.虽然listNode已经可以作为数据存储结构，但是redis为了方便数据管理，还定义了list存储了头节点，尾节点，节点数量
 *      4.hash
 *          1.redis自己构建了字典实现，使用hash表作为底层实现，使用链地址法解决hash冲突，被分配到一个索引的多个键会生成单向链表
 *          2.在对hash表进行扩展或者收缩的时候，会rehash，然后采用头插法，因为redis单线程，所以无需担心环形链表出现
 *          3.rehash是渐进式rehash，采用分治的思想，并不是一次性的操作
 *      5.ziplist
 *          1.压缩表：节省内存，一个压缩列表可以包含任意多个entry，每个节点保存一个字节数组或者一个整数值
 *          2.压缩表并不是对数据利用某种算法压缩，而是将数据按照一定的规则编码在一块连续的内存区域里面
 *      6.intset
 *          1.整数集合，保存整数值的集合，并且保证集合不会出现重复元素
 *      7.bitmaps
 *          1.不是一个真正的数据结构，是建立在string上的以组面向bit操作的集合最多可以设置2的32次方个不同的Bit
 *          2.可以将某个bit设置为0或1，可以统计一定范围内的Bit的数量
 *          3.最大优点是节省空间，40亿用户只要500M就能判断是否登录过
 *          4.跟布隆过滤器差不多，用作大数据去重，但是不存在误判
 *      8.HyperLogLogs
 *          1.用极小的内存消耗来解决数据去重的统计问题，比如每个页面的UV，ip访问去重后的值，存在误差
 *      9.GEO
 *          1.用来操作地址位置，经度维度信息的，并且提供方法进行范围的查询计算
 * 9.布隆过滤器
 *      1.数据结构
 *          1.一个Bit数组
 *          2.如果想映射一个值到其中，需要对这个值用多个不同的hash函数生成多个hash值，并对每个生成的hash值指向bit的位置
 *          3.查询数据时将值hash，得到多个hash值，判断bit数组中相应位置是否为1，为0则返回不存在
 *          4.查询添加快，占用空间小
 *      2.使用场景
 *          1.防止缓存穿透
 *          2.WEB拦截，将请求参数相同的请求拦截掉
 *          3.爬虫的url重复过滤
 *      3.缺点
 *          1.不支持删除
 *          2.存在一定的误判
 *      4.如何减小误判率
 *          1.加大位数组长度
 *          2.增加hash的次数
 *      5.真实使用的参数配置
 *          1.项目中设置的是2的26次方，差不多一亿三千万多，然后误差率在%0.1这样
 *          2.在flink数据入库的时候判重
 *          3.用redisson的布隆过滤器工具类实现的，配置的参数是那样
 *          4.内存占用大小，预估大概在100M这样
 * 10.redis的内存空间满了怎么办(缓存淘汰策略，当redis空间满了才会用这个)
 *      1.修改redis的最大占用内存大小 maxmemory 100mb，通常redis的最大内存设置为服务器内存的四分之三
 *      2.修改内存淘汰策略（当内存满了，就使用内存淘汰策略）
 *          1.noeviction(默认策略)：对于写请求不再提供服务，直接返回错误（DEL请求和部分特殊请求除外）（默认）
 *          2.allkeys-lru：从所有key中使用LRU算法进行淘汰
 *          3.volatile-lru：从设置了过期时间的key中使用LRU算法进行淘汰
 *          4.allkeys-random：从所有key中随机淘汰数据
 *          5.volatile-random：从设置了过期时间的key中随机淘汰
 *          6.volatile-ttl：在设置了过期时间的key中，根据key的过期时间进行淘汰，越早过期的越优先被淘汰
 *          7.allkeys-lfu：从所有key中使用LFU算法进行淘汰
 *          8.volatile-lfu:从已过期的Key中使用lfu算法淘汰
 * 11.redission底层原理
 *      1.跟踪到源码，除了使用很多复杂的信号量的判断外，最主要的是一段lua代码，就是redission加索的核心代码
 *          1.保证redis的加锁是原子性的
 *      2.然后lua代码中是用hset加索的，参数是客户端id，锁的key，还有过期时间
 *      3.互斥机制的保证：判断hash结构中是否存在当前客户端的id，不存在则返回一个锁剩余时间，此实客户端2会进入循环不停尝试加锁
 *      4.可重入性保证：hash结构中存了锁的key和锁的次数，次数加1就是可重入性
 *      5.释放锁：加索的次数为0就del了，另一个客户端就可以加锁了
 *      6.watchDog自动延期机制：如果一个客户端加索,然后业务上超过默认时间30s还想继续延长，有一个看门狗机制，每隔10s会去定时演唱加索的时间
 *      7.最大缺点：就是master节点加索，还没同步给slave节点，结果master节点宕机了，就会导致多个客户端都以为自己加索了
 * 12.redis线上优化（swap，超时，fork，持久化，内存限制，淘汰策略，cpu资源竞争）：
 *      1.redis swap
 *          1.swap是操作系统的行为，当操作系统的内存不足的时候，会将内存中的数据跟磁盘的数据进行交换，放一部分到磁盘上，大大影响内存应用的性能，
 *            因为磁盘的访问速度远远小于内存
 *          2.redis触发swap可能是因为系统内存不足或者其它应用占用内存导致内存不足
 *          3.redis通过 cd /proc/id  cat smaps | egrep '(Swap|Size)'查看swap情况
 *          4.解决方法：
 *              1.将redis部署到单节点上，并且节点不要部署其它服务
 *              2.redis设置最大内存大小
 *              3.redis采用cluster集群，横向扩容内存瓶颈
 *      2.持久化
 *          1.RDB，全量bgsave，非实时，保存RDB的时候需要fork()一个子进程进行操作，fork()的时候可能导致小段时间的服务器停止处理
 *          2.AOF，增量写，实时性高，也是fork()进程，短暂阻塞，占用存储，消耗cpu，因为每s执行一次
 *          3.解决方法：
 *              1.必要的时候关闭aof和rdb，因为fork()子进程会造成短暂停顿，并且消耗内存
 *              2.主从的话可以关闭持久化，只留一台节点进行rdb
 *      3.配置内存
 *          1.内存不应超过机器总内存的50%，否则写rdb文件时可能会导致机器总内存不足，从而io等待或者产生swap，使redis访问速度降低
 *          2.解决方法：设置内存为50%，然后内存到达40%则进行报警
 *      4.超时问题排排查
 *          1.cpu资源竞争：redis服务器上还部署其它服务导致竞争cpu的资源
 *          2.swap问题
 *          3.网络问题：带宽不够，连接数用完（linux文件句柄数加大ulimit），网络延迟，用redis-cli查看
 *          4.持久化影响：rdb和aof fork()子进程导致的cpu和内存消耗
 *      5.查询优化
 *          1.使用批量命令，key设置不宜过长，查询大量的key使用scan不要使用key*
 *          2.使用管道pipeline
 * 13.redis统计用户访问量
 *      1.有序集合zsort
 *          1.可以存储用户登录的时间和id，而且聚合的方式比较多，可以统计不同时段上线的人数
 *          2.但是随着存储的数据越来越多，会更加占用内存
 *      2.集合set
 *          1.每上线一个用户增加添加一条记录，也可以统计不同天数的上线人数，交集或者并集
 *          2.但是随着存储的数据越来越多，会更加占用内存
 *      3.HyperLogLog
 *          1.只想要知道在线用户的人数， 而不需要知道具体的在线用户名单
 *          2.一般用来统计页面的uv
 *          3.每个HyperLogLog只消耗12k内存，内存消耗极小
 *          4.统计存在一定的误差
 *      4.bitmap
 *          1.使用有序集合或者集合能够储存具体的在线用户名单， 但是却需要消耗大量的内存
 *          2.而使用 HyperLogLog 虽然能够有效地减少统计在线用户所需的内存， 但是它却没办法准确地记录具体的在线用户名单
 *          3.能解决上面的问题，并且能进行统计聚合登录人数
 * 14.为什么RedisCluster会设计成16384个槽呢：主要跟心跳机制有关
 *      1.如果槽位为65535个的话，发送心跳包的消息头会达到8k myslots[CLUSTER_SLOTS/8]，浪费带宽
 *          1.这是一个bitmap，每一个位代表一个槽
 *      2.redis的集群主节点数量基本不可能超过1000个
 *      3.槽位越小，节点少的情况下，压缩率高
 * 15.项目中用到redis的什么
 *      1.string：最普通的数据结构，一般缓存都是用这个存，配合注解@Cacheable或者自定义注解使用
 *      2.hash：会存一些属性值，比如人的属性值,key是人的身份证号码，field是属性值
 *      3.list：早期系统是用redis的list来收集日志的，多个服务的日志都lpush到list中，然后系统服务开启一个线程去读取日志，没有的话就阻塞1s
 *      4.bloomFilter：
 *      5.bitmap:统计用户每日的访问的
 *
 * @author
 * @created 2022/2/7 10:42
 */
public class Redis {
}
